import { userStore } from "@/store/useStore";
import router from "@/router";
import {
  AxiosRequestConfig,
  AxiosResponse,
  AxiosError,
  AxiosInstance,
} from "axios";
import { encodeParam } from "./encrypt";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { requestStore } from "@/store/requestStore";

interface newConfig extends AxiosRequestConfig {
  // 设置重复请求次数
  retry?: number;
  // 请求次数
  __retryCount?: number;
}
NProgress.configure({ showSpinner: false });
// 创建axios实例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_API_BASE_URL,
  timeout: 10000,
});

// 请求拦截
service.interceptors.request.use(
  (config: any) => {
    if (!config.noCancel) {
      config.cancelToken = new axios.CancelToken((c) => {
        requestStore().addCancelReq(c);
      });
    }
    NProgress.start();
    const key = sessionStorage.getItem(
      `AUTHTOKEN${sessionStorage.getItem("USERID")}`,
    );
    if (key) {
      config.headers!.token = key;
    }
    return config;
  },
  (err: AxiosError<any, any>) => {
    return Promise.reject(err);
  },
);

// 响应拦截
service.interceptors.response.use(
  (response: AxiosResponse) => {
    NProgress.done();
    const { code, errmsg, returns, errno } = response.data;
    const { url } = response.config;

    if (response.status == 200) {
      if (code == 401 || code == 403) {
        router.replace(`/login?redirect=${encodeParam(url?.toString())}`);
      } else if (
        code == 200 ||
        errno == 0 ||
        errno == 200 ||
        returns == 200 ||
        !errmsg
      ) {
        return response.data;
      } else {
        ElMessage.error(errmsg || "网络连接异常");
        return Promise.reject(new Error(errmsg || "网络连接异常"));
      }
    }
  },
  (error: AxiosError<any, any> & newConfig) => {
    NProgress.done();
    console.log(error);

    if (error instanceof axios.Cancel) return;
    const { url } = error.config as AxiosRequestConfig;
    if (error.response) {
      if (
        error.response.status === 401 ||
        error.response.status === 403 ||
        error.response.data?.message?.includes("请重新登录")
      ) {
        localStorage.clear();
        sessionStorage.clear();
        location.replace(`/login?redirect=${encodeParam(url?.toString())}`);
      }
    }
    if (error.message.indexOf("timeout") !== -1) {
      ElMessage.error("请求超时，请您稍后重试");
    }
    requestAgainSend(error, service);

    // return Promise.reject(error);
  },
);

class request {
  static get<T>(url: string, paramObj: {} = {}, option?: any): Promise<T> {
    return service.get(url, { params: paramObj, ...option });
  }
  static post<T>(url: string, params: {} = {}, option?: any): Promise<T> {
    return service.post(url, params, option);
  }
  static put<T>(url: string, params: {} = {}, option?: any): Promise<T> {
    return service.put(url, params, option);
  }
  static delete<T>(url: string, params: string): Promise<T> {
    return service.delete(url, { data: params });
  }
  static uploadFile<T>(
    url: string,
    params: { file: any },
    option?: any,
  ): Promise<T> {
    const formData = new FormData();
    for (const [key, value] of Object.entries(params)) {
      formData.append(key, value);
    }

    return service.post(url, formData, option);
  }
}

// 判断一个字符串是否为JSON字符串
export const isJsonStr = (str: string) => {
  if (typeof str == "string") {
    try {
      const obj = JSON.parse(str);
      if (typeof obj == "object" && obj) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      console.log("error：" + str + "!!!" + e);
      return false;
    }
  }
};

// 请求重试
async function requestAgainSend(
  err: AxiosError<any, any> & newConfig,
  axios: AxiosInstance,
) {
  const config: AxiosRequestConfig & newConfig = err.config || {};
  if (!config || !config.retry) {
    return Promise.reject(err);
  }
  config.__retryCount = config.__retryCount || 0;
  // 判断是否超过
  if (config.__retryCount >= config.retry) {
    return Promise.reject(err);
  }
  // 重试次数
  config.__retryCount += 1;
  // 延时处理
  const backoff = new Promise(function (resolve) {
    setTimeout(function () {
      resolve("success");
    }, 1000);
  });
  await backoff;
  if (config.data && isJsonStr(config.data)) {
    config.data = JSON.parse(config.data);
  }
  return await axios(config);
}

export default request;
